package com.token.sysflow.action;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.token.base.AgentAction;
import com.token.base.FuncUtil;
import com.token.base.Pl;
import com.token.sql.IntegrateSql;
import com.token.sql.PrepareSql;
import com.token.sql.TableBeanPrepareSql;
import com.token.sysflow.bean.*;

import java.sql.ResultSet;
import java.util.HashMap;


/**
 * 复制流程
 *
 * @author chenjianxiong 2020/5/7
 */
public class CopyFlow implements AgentAction {
    private HashMap<String, String> idMap;
    private String newFlowId = null;
    public void executeAction(FuncUtil f) throws Exception {
    }

    /**
     * @param f    类库
     * @param iSql iSql 类库
     * @throws Exception
     */
    public void executeAction(FuncUtil f, IntegrateSql iSql) throws Exception {
        try {
            iSql.setAutoCommit(false);
            idMap = new HashMap<>();

            FlowFlowInfo flow = new FlowFlowInfo(iSql, f.getUrlQueryString("flowid", true, "流程Id"));
            TableBeanPrepareSql tSql = new TableBeanPrepareSql(flow);

            if (flow.isInitRs()) {
                newFlowId = this.getTypeId("Flow");

                idMap.put(flow.getFlowId(),newFlowId);

                FlowFlowInfo newFlow = copyFlowInfo(f, iSql, flow);

                copyStepInfo(iSql, flow.getFlowId());

                copyPathInfo(iSql, flow.getFlowId());

                updateJsonNode(newFlow);

                f.putJsonData("flowId", newFlowId);

                tSql.close();
                flow.close();
            } else {
                throw new Exception("流程不存在，无法复制！");
            }
            iSql.commit();
        } catch (Exception e) {
            iSql.rollback();
            throw e;
        }
    }

    /**
     *
     * @param iSql
     * @param oldFlowid
     * @throws Exception
     */
    private void copyPathInfo(IntegrateSql iSql,String oldFlowid) throws Exception {
        FlowPathInfo dao = new FlowPathInfo(iSql);
        TableBeanPrepareSql tSql = new TableBeanPrepareSql(dao);
        tSql.setSelectPrepare(" FlowId=? and SysId=? ");
        tSql.setPstValue(1, oldFlowid);
        tSql.setPstValue(2, Pl.getSysId());
        ResultSet rs = tSql.executeQuery();
        String Id = getTypeId("Path");

        int i = 1;
        if (rs.next()) {
            dao.setInsert();
            do {
                String newPathId = Id + (i++);
//                System.out.println("i = " + newPathId);
                dao.initParamToRs(rs);
//                System.out.println("dao.getPathId() = " + dao.getPathId());
                idMap.put(dao.getPathId(), newPathId);
                dao.setSysAddTime(Pl.getCurDataTime());
                dao.setSysEditTime(dao.getSysAddTime());
                dao.setFlowId(newFlowId);
                dao.setPathId(newPathId);
                dao.setFromStepId(idMap.get(dao.getFromStepId()));
                dao.setToStepId(idMap.get(dao.getToStepId()));
                dao.addBatch();
            } while (rs.next());
            dao.executeBatch();
        }
        rs.close();
        dao.close();
        tSql.close();
    }

    /**
     * @param f
     * @param iSql
     * @param flow
     * @return
     * @throws Exception
     */
    private FlowFlowInfo copyFlowInfo(FuncUtil f, IntegrateSql iSql, FlowFlowInfo flow) throws Exception {
        FlowFlowInfo newFlow = new FlowFlowInfo(iSql);
        newFlow.setInsert();
        newFlow.setSysId(Pl.getSysId()); //租户ID //json.getIntValue("SysId")
        newFlow.setSysAddTime(Pl.getCurDataTime()); //创建时间
        newFlow.setSysAddUser(Pl.getCurDataTime()); //创建人
        newFlow.setSysEditTime(Pl.getCurDataTime()); //修改时间
        newFlow.setSysEditUser(f.getEffectiveUserName()); //修改人
        newFlow.setFlowId(newFlowId); //流程ID
        newFlow.setIsActive("0"); //激活流程
        newFlow.setIsDefault("0"); //默认流程
        newFlow.setFlowArea(flow.getFlowArea()); //使用范围

        newFlow.setFlowName(flow.getFlowName()); //流程名称
        newFlow.setFlowVersion(flow.getFlowVersion() + "_copy"); //流程版本
        newFlow.setFlowDesc(flow.getFlowDesc()); //流程描述
        newFlow.setFlowCode(flow.getFlowCode()); //流程编码
        newFlow.setFlowCode1(flow.getFlowCode1()); //yyyyMMdd
        newFlow.setFlowCode2(flow.getFlowCode2()); //流水号位数

        newFlow.setAppKeyId(flow.getAppKeyId()); //流程应用
        newFlow.setJsonNode(flow.getJsonNode()); //节点数据
        newFlow.executeUpdate();
        newFlow.setKeyId(newFlowId);
        return newFlow;
    }

    /**
     *
     * @param flow
     * @throws Exception
     */
    private void updateJsonNode(FlowFlowInfo flow) throws Exception{
        JSONObject jsonObject = JSON.parseObject(flow.getJsonNode());
        JSONArray nodes = jsonObject.getJSONArray("nodes");
        for(int ii = 0;ii<nodes.size();ii++){
            JSONObject node = nodes.getJSONObject(ii);
            if(node.getString("datatype").equals("lane") || node.getString("datatype").equals("text")){

            }else{
                String nn = idMap.get("Step" + node.getString("id"));
                node.put("id",nn.replaceAll("Step",""));
            }
        }

        JSONArray edges = jsonObject.getJSONArray("edges");
        for(int i = 0;i<edges.size();i++){
            JSONObject node = edges.getJSONObject(i);
            String nn = idMap.get("Path" + node.getString("id"));
            node.put("id",nn.replaceAll("Path",""));
            String source = "Step"+ node.getString("source");
            String newSource = idMap.get(source);
            node.put("source",newSource.replaceAll("Step",""));

            String target = "Step"+ node.getString("target");
            String newTarget = idMap.get(target);
            node.put("target",newTarget.replaceAll("Step",""));
        }
        flow.setUpdateCur();
        flow.setJsonNode(jsonObject.toJSONString());
        flow.executeUpdate();
    }
    /**
     * @param iSql
     * @param oldFlowId
     * @return
     * @throws Exception
     */
    private void copyStepInfo(IntegrateSql iSql, String oldFlowId) throws Exception {

        FlowStepApproverVth vth = new FlowStepApproverVth(iSql);
        FlowStepSubflow subflow = new FlowStepSubflow(iSql);
        FlowStepSubflowSub flowStepSubflowSub = new FlowStepSubflowSub(iSql);
        FlowStepNotifySub flowStepNotifySub = new FlowStepNotifySub(iSql);
        FlowStepSubflowVth subflowVth = new FlowStepSubflowVth(iSql);
        FlowStepNotifyVth notifySub = new FlowStepNotifyVth(iSql);
        FlowStepBasic basic = new FlowStepBasic(iSql);
        FlowStepControl control = new FlowStepControl(iSql);
        FlowStepSwitchFunc switchFunc = new FlowStepSwitchFunc(iSql);
        FlowStepApprover approver = new FlowStepApprover(iSql);

        vth.setInsert();
        notifySub.setInsert();
        notifySub.setFlowId(newFlowId);
        subflowVth.setInsert();
        subflowVth.setFlowId(newFlowId);
        flowStepSubflowSub.setFlowId(newFlowId);
        PrepareSql prepareSql = new PrepareSql(iSql);

        prepareSql.setPrepare("select * from v_Sys_FlowStep where flowId=? and SysId=?");
        prepareSql.setPstValue(1, oldFlowId);
        prepareSql.setPstValue(2, Pl.getSysId());
        ResultSet rs = prepareSql.executeQuery();

        PrepareSql prepareSql2 = new PrepareSql(iSql);
        String Id = getTypeId("Step");

        int i = 1;




        //Flow_StepApprover FlowId PreHandler

        //Flow_StepApproverVth FlowId StepId

        //Flow_StepSubflow FlowId

        //Flow_PathInfo FlowId FromStepId ToStepId

        //Flow_StepNotifyVth FlowId
        while (rs.next()) {
            String newStepId = Id + (i++);
            idMap.put(rs.getString("StepId"), newStepId);
            basic.setInsert();
            basic.initParamToRs(rs);
            //Flow_StepBasic FlowId
            //Flow_StepControl FlowId
            //Flow_StepSwitchFunc FlowId
            basic.setFlowId(newFlowId); //流程ID
            basic.setStepId(newStepId); //环节ID
            basic.executeUpdate();

            control.setInsert();
            control.initParamToRs(rs);
            control.setStepId(newStepId); //环节ID
            control.setFlowId(newFlowId); //流程ID
            control.executeUpdate();

            switchFunc.setInsert();
            switchFunc.initParamToRs(rs);
            switchFunc.setStepId(newStepId); //环节ID
            switchFunc.setFlowId(newFlowId); //流程ID
            switchFunc.executeUpdate();

            approver.setInsert();
            approver.initParamToRs(rs);
            approver.setStepId(newStepId); //环节ID
            approver.setFlowId(newFlowId); //流程ID
            approver.setPreHandler("");
            approver.executeUpdate();

            //多值办理人
            copyApproverVth(vth, prepareSql2, basic.getKeyName(), newStepId, rs.getString(basic.getKeyName()));


            //知会行项目
            copyNotifySub(flowStepNotifySub, notifySub, prepareSql2, basic.getKeyName(), newStepId, rs.getString(basic.getKeyName()));

            //子流程行项目
            if ("task_zlc".equals(basic.getStepType())) { // 子流程
                subflow.setInsert();
                subflow.setStepId(newStepId); //环节ID
                subflow.setFlowId(newFlowId); //流程ID
                subflow.setSubflowReSave(rs.getString("SubflowReSave")); //初始化子流程
                subflow.setSubflowSelect(rs.getString("SubflowSelect")); //可选择子流程
                subflow.setSubflowShowALL(rs.getString("SubflowShowALL")); //是否全部显示
                subflow.executeUpdate();
                copySubflowSub(flowStepSubflowSub, subflowVth, prepareSql2, basic.getKeyName(), newStepId, rs.getString(basic.getKeyName()));
            }

        }

        rs.close();
        vth.close();
        basic.close();
        approver.close();
        control.close();
        switchFunc.close();
        subflow.close();
    }

    /**
     * @param vth
     * @param prepareSql2
     * @param newStepId
     * @param oldStepId
     * @throws Exception
     */
    private void copyApproverVth(FlowStepApproverVth vth, PrepareSql prepareSql2, String keyName, String newStepId, String oldStepId) throws Exception {
        prepareSql2.setPrepare(vth.selectCode().append(" where ").append(keyName).append("=?"));
        prepareSql2.setPstValue(1, oldStepId);
        ResultSet rs2 = prepareSql2.executeQuery();
        if (rs2.next()) {
            do {
                vth.initParamToRs(rs2);
                vth.setFlowId(newFlowId);
                vth.setStepId(newStepId);
                vth.addBatch();
            } while (rs2.next());
            vth.executeBatch();
        }
        rs2.close();
    }

    /**
     * @param flowStepSubflowSub
     * @param Vth
     * @param prepareSql2
     * @param keyName
     * @param newStepId
     * @param oldStepId
     * @throws Exception
     */
    private void copySubflowSub(FlowStepSubflowSub flowStepSubflowSub, FlowStepSubflowVth Vth, PrepareSql prepareSql2, String keyName, String newStepId, String oldStepId) throws Exception {
        prepareSql2.setPrepare(flowStepSubflowSub.selectCode().append(" where ").append(keyName).append("=?"));
        prepareSql2.setPstValue(1, oldStepId);
        ResultSet rs2 = prepareSql2.executeQuery();
        String id = getTypeId("SubFlow");
        if (rs2.next()) {
            int i = 1;
            do {
                String subFlowId = id + (i++);
                //Flow_StepSubflow_Sub StepId FlowId
                flowStepSubflowSub.initParamToRs(rs2);
                flowStepSubflowSub.setFlowId(newFlowId);
                flowStepSubflowSub.setSubFlowID(subFlowId); //主键
                flowStepSubflowSub.setStepId(newStepId);
                flowStepSubflowSub.addBatch();
                copySubflowSubVth(Vth, prepareSql2, flowStepSubflowSub.getKeyName(),subFlowId, rs2.getString(flowStepSubflowSub.getKeyName()));
            } while (rs2.next());
            flowStepSubflowSub.executeBatch();
        }
        rs2.close();
    }

    /**
     * @param vth
     * @param prepareSql2
     * @param newId
     * @param oldId
     * @throws Exception
     */
    private void copySubflowSubVth(FlowStepSubflowVth vth, PrepareSql prepareSql2, String keyName, String newId, String oldId) throws Exception {
        prepareSql2.setPrepare(vth.selectCode().append(" where ").append(keyName).append("=?"));
        prepareSql2.setPstValue(1, oldId);
        ResultSet rs2 = prepareSql2.executeQuery();
        if (rs2.next()) {
            do {
                vth.initParamToRs(rs2);
                vth.setFlowId(newFlowId);
                vth.setSubFlowID(newId);
                vth.addBatch();
            } while (rs2.next());
            vth.executeBatch();
        }
        rs2.close();
    }

    /**
     * @param flowStepNotifySub
     * @param Vth
     * @param prepareSql2
     * @param newStepId
     * @param oldStepId
     * @throws Exception
     */
    private void copyNotifySub(FlowStepNotifySub flowStepNotifySub, FlowStepNotifyVth Vth, PrepareSql prepareSql2, String keyName, String newStepId, String oldStepId) throws Exception {
        prepareSql2.setPrepare(flowStepNotifySub.selectCode().append(" where ").append(keyName).append("=?"));
        prepareSql2.setPstValue(1, oldStepId);
        ResultSet rs2 = prepareSql2.executeQuery();
        String id = getTypeId("Notify");
        if (rs2.next()) {
            int i = 1;
            do {
                //Flow_StepNotify_Sub FlowId StepId

                String notifyId = id + (i++);
                flowStepNotifySub.initParamToRs(rs2);
                flowStepNotifySub.setFlowId(newFlowId);
                flowStepNotifySub.setNotifyID(notifyId); //主键
                flowStepNotifySub.setStepId(newStepId); //环节ID
                flowStepNotifySub.addBatch();
                copyNotifySubVth(Vth, prepareSql2, notifyId, flowStepNotifySub.getKeyName(), rs2.getString(flowStepNotifySub.getKeyName()));
            } while (rs2.next());
            flowStepNotifySub.executeBatch();
        }
        rs2.close();
    }

    /**
     * @param vth
     * @param prepareSql2
     * @param newId
     * @param oldId
     * @throws Exception
     */
    private void copyNotifySubVth(FlowStepNotifyVth vth, PrepareSql prepareSql2, String keyName, String newId, String oldId) throws Exception {
        prepareSql2.setPrepare(vth.selectCode().append(" where ").append(keyName).append("=?"));
        prepareSql2.setPstValue(1, oldId);
        ResultSet rs2 = prepareSql2.executeQuery();
        if (rs2.next()) {
            do {
                vth.initParamToRs(rs2);
                vth.setFlowId(newFlowId);
                vth.setNotifyID(newId);
                vth.addBatch();
            } while (rs2.next());
            vth.executeBatch();
        }
        rs2.close();
    }

    /**
     * 生成Id
     *
     * @param str 前
     * @return
     */
    private String getTypeId(String str) {
        StringBuilder buf;
        synchronized (CopyFlow.class) {
            buf = new StringBuilder(50);
            buf.append(str)
                    .append(System.currentTimeMillis())
                    .append("_")
                    .append(((int) (Math.random() * 10000)));
        }
        return buf.toString();
    }
}
